/*
 原型及原型链:

 原型链是一种机制，指的是 JavaScript 每个对象都有一个内置的 __proto__ 属性指向创建它的构造函数的 prototype（原型）属性。
 原型链的作用是为了实现对象的继承，要理解原型链，
 需要先从函数对象、constructor、new、prototype、__proto__ 这五个概念入手。



    __proto__:
        1）对象特有
        2）指向上层(创建自己的那个构造函数)的原型对象(prototype)，即：实例对象.__proto__ === 构造函数.prototype
        3) 对象从prototype继承属性和方法

    prototype:
        1）函数特有
        2）用于存储要共享的属性和方法

    constructor
        1）函数特有，定义在prototype里面
        2）通过new创建实例时，该实例便继承力prototype的原型属性和方法


    对象是由构造函数创建的
        1、Object：既是对象，又是构造函数
            1）作为函数：Object.prototype是原型链的顶端，Object.prototype.__proto__ = null
            2）作为对象：Object.__proto__ = Function.prototype

        2、Function：既是对象，又是构造函数
            1）作为对象：Function.__proto__ = Function.prototype
            2）作为函数：Function.prototype用于共享，而Function.prototype.__proto__继承自Object.prototype

        3、Array和普通函数与第2点一样



    结论：
        1、原型链顶端是Object.prototype
        2、所有对象（包括Object、Function、Array、普通函数），它们的__proto__都指向Function.prototype。
            记住一点，构造函数创建的实例对象都是Fucntion的实例

        3、除了Oblect，所有对象（应该叫构造函数）的prototype,都继承自Object.prototype


    new 操作符:
    1.创建一个新对象；
    2.将构造函数的作用域赋给新对象（因此 this 就指向了这个新对象）；
    3.执行构造函数中的代码（为这个新对象添加属性）；
    4.返回新对象。

 **/

/***
一、所有构造器/函数的__proto__都指向Function.prototype，
甚至包括根构造器Object及Function自身。
所有构造器都继承了Function.prototype的属性及方法。
Function.prototype它是一个空函数（Empty function）
 */

//js内置构造器/对象
console.log(Number.__proto__ === Function.prototype ) // true
console.log(Boolean.__proto__ === Function.prototype )// true
console.log(String.__proto__ === Function.prototype ) // true
console.log(Object.__proto__ === Function.prototype ) // true
console.log(Function.__proto__ === Function.prototype) // true
console.log(Array.__proto__ === Function.prototype )  // true
console.log(RegExp.__proto__ === Function.prototype)  // true
console.log(Error.__proto__ === Function.prototype )  // true
console.log(Date.__proto__ === Function.prototype)    // true
console.log(Function.prototype)  // [Function]可见上面的值都是[Function]

console.log()
//注意下面这两个不是内置构造函数，而是内置对象
//Math，JSON是以对象形式存在的，无需new。它们的__proto__是Object.prototype。
console.log(Math.__proto__ === Function.prototype)    // false
console.log(JSON.__proto__ === Function.prototype)    // false
console.log(Math.__proto__ === Object.prototype)    // true
console.log(JSON.__proto__ === Object.prototype)    // true


console.log()
//自定义的构造器
//1.函数声明
function Foo(){}
console.log(Foo.__proto__ === Function.prototype)    // true

//2.函数表达式
let Fn = function(){}
console.log(Fn.__proto__ === Function.prototype)    // true

console.log()

//Function.prototype的__proto__是谁呢？
console.log(Function.prototype.__proto__ === Object.prototype) // true
//最后Object.prototype的__proto__是谁？
console.log(Object.prototype.__proto__ === null) // true

console.log('--------------------------1-----------------------------')
/**----------------------------------1--------------------------------------*/

/**
 * Function.prototype也是唯一一个typeof XXX.prototype为 “function”的prototype。
 * 其它的构造器的prototype都是一个对象。
 */
console.log(typeof Function.prototype) // function
console.log(typeof Object.prototype)   // object
console.log(typeof Number.prototype)   // object
console.log(typeof Boolean.prototype)  // object
console.log(typeof String.prototype)   // object
console.log(typeof Array.prototype)    // object
console.log(typeof RegExp.prototype)   // object
console.log(typeof Error.prototype)    // object
console.log(typeof Date.prototype)     // object
console.log(typeof Object.prototype)   // object
//注意下面两个同样是js内置对象，但情况不一样
console.log(typeof Math.prototype)   // undefined
console.log(typeof JSON.prototype)   // undefined

console.log()
console.log('------------------------2-------------------------------')


/***
 * 二、所有对象的__proto__都指向其构造器的prototype
 */

//JavaScript引擎内置构造器与其实例
let obj = {name: 'jack'}
let arr = [1,2,3]
let reg = /hello/g
let date = new Date
let err = new Error('exception')
let string = 'ssss'
let num = 2
let boolean = true

console.log(obj.__proto__ === Object.prototype) // true
console.log(arr.__proto__ === Array.prototype)  // true
console.log(reg.__proto__ === RegExp.prototype) // true
console.log(date.__proto__ === Date.prototype)  // true
console.log(err.__proto__ === Error.prototype)  // true
console.log(string.__proto__ === String.prototype)  // true
console.log(num.__proto__ === Number.prototype)  // true
console.log(boolean.__proto__ === Boolean.prototype)  // true

//自定义构造器与其实例
function F(){}
const f = new F()
console.log(f.__proto__ === F.prototype) // true

console.log()
console.log('------------------------3-------------------------------')

/**
 * 每个对象都有一个constructor属性，可以获取它的构造器
 */
console.log(f.__proto__ === f.constructor.prototype) // true
console.log(obj.__proto__ === obj.constructor.prototype) // true
console.log(arr.__proto__ === arr.constructor.prototype) // true
console.log(date.__proto__ === date.constructor.prototype) // true
console.log(err.__proto__ === err.constructor.prototype) // true
console.log(string.__proto__ === string.constructor.prototype) // true
console.log(num.__proto__ === num.constructor.prototype) // true
console.log(boolean.__proto__ === boolean.constructor.prototype) // true



console.log()
console.log(Number.__proto__ === Number.constructor.prototype ) // true
console.log(Boolean.__proto__ === Boolean.constructor.prototype ) // true
console.log(String.__proto__ === String.constructor.prototype ) // true
console.log(Object.__proto__ === Object.constructor.prototype ) // true
console.log(Function.__proto__ === Function.constructor.prototype ) // true
console.log(Array.__proto__ === Array.constructor.prototype ) // true
console.log(RegExp.__proto__ === RegExp.constructor.prototype ) // true
console.log(Error.__proto__ === Error.constructor.prototype ) // true
console.log(Date.__proto__ === Date.constructor.prototype ) // true

console.log()
console.log('------------------------4-------------------------------')


console.log(4.1)
console.log(num.__proto__ ) // F [Number: 0]
console.log(string.__proto__ ) // [String: '']
console.log(arr.__proto__ ) // []
console.log(obj.__proto__ ) // {}
console.log(boolean.__proto__ ) // [Boolean: false]
console.log(err.__proto__ ) //Error {}
console.log(date.__proto__ ) //Date {}
console.log(reg.__proto__ ) //RegExp {}
console.log(f.__proto__ ) // F {}

console.log(4.2)
console.log(Number.__proto__  ) // [Function]
console.log(Boolean.__proto__  )// [Function]
console.log(String.__proto__  ) // [Function]
console.log(Object.__proto__  ) // [Function]
console.log(Function.__proto__ ) // [Function]
console.log(Array.__proto__  )  // [Function]
console.log(RegExp.__proto__ )  // [Function]
console.log(Error.__proto__  )  // [Function]
console.log(Date.__proto__ )    // [Function]


console.log(4.3)
console.log( Function.prototype) // [Function]
console.log( Object.prototype)   // {}
console.log( Number.prototype)   // [Number: 0]
console.log( Boolean.prototype)  // [Boolean: false]
console.log( String.prototype)   // [String: '']
console.log( Array.prototype)    // []
console.log( RegExp.prototype)   // RegExp {}
console.log( Error.prototype)    // Error {}
console.log( Date.prototype)     // Date {}
console.log( Object.prototype)   // {}



console.log()
console.log('------------------------5-------------------------------')
console.log(f.__proto__.__proto__.__proto__) // null
console.log(num.__proto__.__proto__.__proto__) // null
console.log(string.__proto__.__proto__.__proto__) // null
console.log(obj.__proto__.__proto__) // null
console.log(arr.__proto__.__proto__.__proto__) // null
console.log(boolean.__proto__.__proto__.__proto__) // null
console.log(reg.__proto__.__proto__.__proto__) // null
console.log(date.__proto__.__proto__.__proto__) // null
console.log(err.__proto__.__proto__.__proto__) // null

console.log()
